﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using DataModels.Common;
using DataModels.Enumerations;
using GenericTools.ReportProcessing;
using GenericTools.Models;
using GenericTools.IQServices;

namespace GenericTools
{
    public class Merging
    {
        #region Constants
        #region Others
        private const string FACCODE = "FACCODE";
        private const string MONTH = "MONTH";
        private const string YEAR = "YEAR";
        #endregion
        #endregion

        #region Class Variables
        private static IQService webService;
        #endregion
        
        #region Constructors
        static Merging()
        {
            webService = new IQServices.IQService();
            webService.Url = AppConfiguration.WebServiceURL;
        }
        #endregion

        public static DataTable GetAllReportMerge()
        {
            DataTable dataTable = null;
            string query = String.Empty;
            switch (AppConfiguration.AccessMethod)
            {
                case DataAccessMethod.DIRECT_ACCESS:
                case DataAccessMethod.OFFLINE_DIRECT_ACCESS:
                    query = @"SELECT [MergeId], [Name], [Description] FROM ReportMerge ORDER BY [Name] ASC";
                    dataTable = GenericDataAccess.RunSelectQuery(query);
                    break;

                case DataAccessMethod.OFFLINE_DATA_ACCESS:
                    query = @"SELECT [MergeId], [Name], [Description] FROM ReportMerge ORDER BY [Name] ASC";
                    DbCommand command = GenericDataAccess.CreateCacheDBCommand();
                    command.CommandText = query;
                    dataTable = GenericDataAccess.ExecuteSelectCommand(command);
                    break;

                case DataAccessMethod.WEB_SERVICES:
                    string output = webService.GetAllReportMerge();
                    dataTable = DataTransformation.Deserialize(output);
                    break;
            }

            return dataTable;
        }

        public static DataTable GetDestinationMergingReport(int mergeId)
        {
            DataTable dataTable = null;
            DbCommand command = null;
            DbParameter param = null;
            string query = String.Empty;
            switch (AppConfiguration.AccessMethod)
            {
                case DataAccessMethod.DIRECT_ACCESS:
                case DataAccessMethod.OFFLINE_DIRECT_ACCESS:
                    query = @"SELECT [RepID], [ReportName], [RepVersion], [Description],[Comments] 
                        FROM Report AS r INNER JOIN MergingReports AS mr ON r.RepID=mr.DestinationReportId
                        WHERE mr.MergeId = @MergeId";
                    command = GenericDataAccess.CreateCommand();
                    command.CommandType = CommandType.Text;
                    command.CommandText = query;
                    
                    param = command.CreateParameter();
                    param.DbType = DbType.Int32;
                    param.ParameterName = "@MergeId";
                    param.Value = mergeId;
                    command.Parameters.Add(param);
                    dataTable = GenericDataAccess.ExecuteSelectCommand(command);
                    break;

                case DataAccessMethod.OFFLINE_DATA_ACCESS:
                    query = @"SELECT [RepID], [ReportName], [RepVersion], [Description],[Comments] 
                        FROM Report AS r INNER JOIN MergingReports AS mr ON r.RepID=mr.DestinationReportId
                        WHERE mr.MergeId = @MergeId";
                    command = GenericDataAccess.CreateCacheDBCommand();
                    param = command.CreateParameter();
                    param.DbType = DbType.Int32;
                    param.ParameterName = "@MergeId";
                    param.Value = mergeId;
                    command.Parameters.Add(param);
                    dataTable = GenericDataAccess.ExecuteSelectCommand(command);
                    break;

                case DataAccessMethod.WEB_SERVICES:
                    string output = webService.GetDestinationMergingReport(mergeId);
                    dataTable = DataTransformation.Deserialize(output);
                    break;
            }

            return dataTable;
        }

        public static DataTable GetSourceMergingReports(int mergeId)
        {
            DataTable dataTable = null;
            DbCommand command = null;
            DbParameter param = null;
            string query = String.Empty;
            switch (AppConfiguration.AccessMethod)
            {
                case DataAccessMethod.DIRECT_ACCESS:
                case DataAccessMethod.OFFLINE_DIRECT_ACCESS:
                    query = @"SELECT [RepID], [ReportName], [RepVersion], [Description],[Comments] 
                        FROM Report AS r INNER JOIN MergingReports AS mr ON r.RepID=mr.SourceReportId
                        WHERE mr.MergeId = @MergeId";
                    command = GenericDataAccess.CreateCommand();
                    command.CommandType = CommandType.Text;
                    command.CommandText = query;
                    
                    param = command.CreateParameter();
                    param.DbType = DbType.Int32;
                    param.ParameterName = "@MergeId";
                    param.Value = mergeId;
                    command.Parameters.Add(param);
                    dataTable = GenericDataAccess.ExecuteSelectCommand(command);
                    break;

                case DataAccessMethod.OFFLINE_DATA_ACCESS:
                    query = @"SELECT [RepID], [ReportName], [RepVersion], [Description],[Comments] 
                        FROM Report AS r INNER JOIN MergingReports AS mr ON r.RepID=mr.SourceReportId
                        WHERE mr.MergeId = @MergeId";
                    command = GenericDataAccess.CreateCacheDBCommand();
                    command.CommandText = query;                    
                    
                    param = command.CreateParameter();
                    param.DbType = DbType.Int32;
                    param.ParameterName = "@MergeId";
                    param.Value = mergeId;
                    command.Parameters.Add(param);
                    dataTable = GenericDataAccess.ExecuteSelectCommand(command);
                    break;

                case DataAccessMethod.WEB_SERVICES:
                    string output = webService.GetSourceMergingReport(mergeId);
                    dataTable = DataTransformation.Deserialize(output);
                    break;
            }

            return dataTable;
        }

        public static DataTable GetReportDataMerging(int mergeId)
        {
            DataTable dataTable = null;
            DbCommand command = null;
            DbParameter param = null;
            string query = String.Empty;
            switch (AppConfiguration.AccessMethod)
            {
                case DataAccessMethod.DIRECT_ACCESS:
                case DataAccessMethod.OFFLINE_DIRECT_ACCESS:
                    query = @"SELECT [DataMergeId], [MergeId], [DestinationIndicator], [SourceIndicator],[Comments] 
                        FROM ReportDataMerging WHERE MergeId = @MergeId";
                    command = GenericDataAccess.CreateCommand();
                    command.CommandType = CommandType.Text;
                    command.CommandText = query;
                    
                    param = command.CreateParameter();
                    param.DbType = DbType.Int32;
                    param.ParameterName = "@MergeId";
                    param.Value = mergeId;
                    command.Parameters.Add(param);
                    dataTable = GenericDataAccess.ExecuteSelectCommand(command);
                    break;

                case DataAccessMethod.OFFLINE_DATA_ACCESS:
                    query = @"SELECT [DataMergeId], [MergeId], [DestinationIndicator], [SourceIndicator],[Comments] 
                        FROM ReportDataMerging WHERE MergeId = @MergeId";
                    command = GenericDataAccess.CreateCacheDBCommand();
                    command.CommandType = CommandType.Text;
                    command.CommandText = query;                    
                    
                    param = command.CreateParameter();
                    param.DbType = DbType.Int32;
                    param.ParameterName = "@MergeId";
                    param.Value = mergeId;
                    command.Parameters.Add(param);
                    dataTable = GenericDataAccess.ExecuteSelectCommand(command);
                    break;

                case DataAccessMethod.WEB_SERVICES:
                    string output = webService.GetReportDataMerging(mergeId);
                    dataTable = DataTransformation.Deserialize(output);
                    break;
            }

            return dataTable;
        }

        public static DataModels.Common.ReportingMessage SendReport(string senderNum, string reportingText/*, string userSignature*/,
            SMSReportingFormat smsFormat, DataInputingMethod inputMethod)
        {
            var reportingMode = AppConfiguration.SameMonthReporting 
                ? ReportingMode.ALLOW_SAME_MONTH_REPORTING 
                : ReportingMode.DEFAULT;
            reportingMode |= ReportingMode.IGNORE_EXPECTED_REPORTS;

            DataModels.Common.ReportingMessage reportingMessage = new DataModels.Common.ReportingMessage();
            switch (AppConfiguration.AccessMethod)
            {
                case DataAccessMethod.DIRECT_ACCESS:
                    ReportProcessor reportProcessor = null;
                    //string errorText = String.Empty;
                    reportProcessor = new ReportProcessor(senderNum, reportingText, ReportingType.VALIDATION, 
                        reportingMode, smsFormat, inputMethod);
                    reportProcessor.ReportBussinessRulesFailed += ReportProcessor.HandleMTUHAMCReport;
                    reportProcessor.SavingReport += ReportProcessor.HandleInconsitentReports;
                    reportProcessor.Submit();

                    //errorText = GetTranslationText("IQSMS", reportProcessor.ErrorTextLabelID);
                    reportingMessage.Message = reportProcessor.ErrorText; ;
                    reportingMessage.Status = reportProcessor.ErrorTextLabelID;
                    break;

                case DataAccessMethod.WEB_SERVICES:
                    string output = webService.SendMergingReport(senderNum, reportingText);//, userSignature);
                    DataTable dataTable = DataTransformation.Deserialize(output);
                    DataRow row = dataTable.Rows[0];
                    reportingMessage.Status = Int32.Parse(row["Status"].ToString());
                    reportingMessage.Message = row["Message"].ToString();
                    break;
            }
            return reportingMessage;
        }

        private static GenericTools.Models.MergingOperationStatus MergeReports(int mergeId, bool overwrite, DataTable requiredFacilities,
            int startYear, int startMonth, int endYear, int endMonth, string senderNum)
        {
            int totalSubmitted = 0;
            int totalRejected = 0;
            int totalAlreadyExisting = 0;
            int totalReportAccepted = 0;
            int totalReportOverwritten = 0;
            bool merged = false;
            try
            {
                #region Pre-processing the request
                DataTable sourceMergingReport = Merging.GetSourceMergingReports(mergeId);
                List<int> sourceReports = new List<int>();
                foreach (DataRow r in sourceMergingReport.Rows)
                {
                    string sRepId = r["RepID"].ToString();
                    int iRepId = Int32.Parse(sRepId);
                    sourceReports.Add(iRepId);
                }

                #endregion

                #region Getting the number of final reports required
                Dictionary<string, Dictionary<string, string>> finalReports = new Dictionary<string, Dictionary<string, string>>();
                int currentYear = startYear;
                int currentMonth = startMonth;
                bool okToContinue = true;

                List<string> reportingTexts = new List<string>();
                while (okToContinue)
                {
                    string monthText = String.Format("{0} {1}", Utilities.GetMonthText(currentMonth), currentYear);
                    // Contains facility code as key and value being the dictionary to hold short code and report data
                    Dictionary<string, Dictionary<string, string>> facilityReport = new Dictionary<string, Dictionary<string, string>>();

                    bool reportKeywordFound = false;
                    string reportKeyword = String.Empty;
                    foreach (DataRow r in requiredFacilities.Rows)
                    {
                        bool reportMissing = false;
                        string facilityCode = null;
                        string facilityName = null;
                        try
                        {
                            facilityCode = r["FacCode"].ToString();
                            facilityName = r["FacName"].ToString();
                        }
                        catch   // Some queries i.e. Nation uses Facility Code, BIG MISTAKES!!!
                        {
                            facilityCode = r["Facility Code"].ToString();
                            facilityName = r["Facility Name"].ToString();
                        }

                        #region Retrieving Required Source Reports for merging
                        Dictionary<int, Dictionary<string, string>> sourceFacilityMonthlyReports = new Dictionary<int, Dictionary<string, string>>();
                        foreach (int repId in sourceReports)
                        {
                            DataTable submittedReport = Utilities.GetSumittedFacilityReport(facilityCode,
                                repId, currentYear, currentMonth, currentYear, currentMonth);
                            if (submittedReport.Rows.Count != 1)
                            {
                                reportMissing = true;
                                break;
                            }

                            DataTable dataTable = Utilities.GetFacilityReport(facilityCode, repId,
                                currentYear, currentMonth, currentYear, currentMonth, true);

                            Dictionary<string, string> sourceFacilityMonthlyReport = new Dictionary<string, string>();
                            sourceFacilityMonthlyReport[FACCODE] = facilityCode;
                            sourceFacilityMonthlyReport[MONTH] = currentMonth.ToString();
                            sourceFacilityMonthlyReport[YEAR] = currentYear.ToString();

                            foreach (DataRow x in dataTable.Rows)
                            {
                                string key = x["Data Description"].ToString();
                                string value = x["Data"].ToString();
                                sourceFacilityMonthlyReport[key] = value;
                            }
                            sourceFacilityMonthlyReports[repId] = sourceFacilityMonthlyReport;
                        }
                        #endregion

                        if (reportMissing) continue;    // Skip this facility, something is missing
                        //Dictionary<string, string> facilityMonthlyReport = new Dictionary<string, string>();

                        #region Generate the destination report from merged source reports
                        DataTable reportMergeIndicators = Merging.GetReportDataMerging(mergeId);
                        Dictionary<string, string> destinationFacilityMonthlyReport = new Dictionary<string, string>();
                        foreach (DataRow a in reportMergeIndicators.Rows)
                        {
                            string destinationIndicator = a["DestinationIndicator"].ToString();
                            string[] destinationIndicatorComponents = destinationIndicator.Split(new string[] { "." }, StringSplitOptions.RemoveEmptyEntries);  // eg.{3}.FACCODE
                            string destinationShortCode = destinationIndicatorComponents[1];

                            if (!reportKeywordFound)
                            {
                                string[] keywordParts = destinationIndicator.Split(new string[] { "." }, StringSplitOptions.RemoveEmptyEntries);
                                string key = keywordParts[0].Replace("{", "");
                                key = key.Replace("}", "");
                                int id = Int32.Parse(key);
                                DataTable reportInfo = Utilities.GetReportDetails(id);
                                reportKeyword = reportInfo.Rows[0]["RepVersion"].ToString();
                                reportKeywordFound = true;
                            }

                            string sourceIndicator = a["SourceIndicator"].ToString();
                            var sourceDefinition = sourceIndicator;
                            string outputValue = string.Empty;

                            string[] components = sourceDefinition.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                            ArithmeticOperation operation = ArithmeticOperation.ADD;
                            string sValue = string.Empty;
                            bool valueIsNumeric = false;
                            int value = 0;
                            int currentValue = 0;

                            foreach (string component in components)
                            {
                                switch (component)
                                {
                                    case "+":
                                        operation = ArithmeticOperation.ADD;
                                        break;

                                    case "-":
                                        operation = ArithmeticOperation.SUBTRACT;
                                        break;

                                    default:
                                        // Now this is the fix when a fixed number is provided. The trick used here for
                                        // fixed number is to have a shortcode section replaced by that fixe number
                                        // enclosed with square brackets. eg {50}.[25]
                                        if (component.StartsWith("[")) sValue = component.Replace("[", string.Empty).Replace("]", string.Empty);
                                        else
                                        {
                                            string[] parts = component.Split(new string[] { "." }, StringSplitOptions.RemoveEmptyEntries);
                                            string sSourceReportId = parts[0].Replace("{", string.Empty).Replace("}", string.Empty);
                                            int sourceReportId = int.Parse(sSourceReportId);
                                            string shortCode = parts[1];

                                            Dictionary<string, string> sourceData = new Dictionary<string, string>();
                                            sourceData = sourceFacilityMonthlyReports[sourceReportId];
                                            sValue = sourceData[shortCode];


                                            // TODO: Remove this hardcoding of FACCODE short code, the potential error is the convertion of 
                                            // facility code to number. eg. 04010100 will be treated as 4010100 instead of being treated as
                                            // the text.
                                            if (shortCode == FACCODE)
                                            {
                                                valueIsNumeric = false;
                                                continue;
                                            }
                                        }
                                        
                                        bool converted = int.TryParse(sValue, out currentValue);
                                        if (converted) valueIsNumeric = true;
                                        else valueIsNumeric = false;

                                        if (valueIsNumeric)
                                        {
                                            switch (operation)
                                            {
                                                case ArithmeticOperation.ADD:
                                                    value += currentValue;
                                                    break;

                                                case ArithmeticOperation.SUBTRACT:
                                                    value -= currentValue;
                                                    break;
                                            }
                                        }
                                        break;
                                }
                            }

                            if (valueIsNumeric) outputValue = value.ToString();
                            else outputValue = sValue;

                            destinationFacilityMonthlyReport[destinationShortCode] = outputValue;
                        }
                        #endregion

                        #region Prepare Reporting Text, just like SMS message
                        StringBuilder sBuilder = new StringBuilder();
                        sBuilder.Append(reportKeyword);
                        sBuilder.Append(".");
                        foreach (string x in destinationFacilityMonthlyReport.Keys)
                        {
                            string xx = destinationFacilityMonthlyReport[x];
                            sBuilder.Append(xx);
                            sBuilder.Append(",");
                        }
                        string reportingText = sBuilder.ToString();
                        reportingText = reportingText.Substring(0, reportingText.Length - 1);
                        reportingTexts.Add(reportingText);
                        #endregion
                    }

                    #region Iteration Determinant
                    reportKeywordFound = false;
                    currentMonth++;
                    if (currentMonth > 12)
                    {
                        currentYear++;
                        currentMonth = 1;
                    }
                    if (currentYear > endYear) okToContinue = false;
                    else
                    {
                        if (currentYear == endYear)
                        {
                            if (currentMonth > endMonth) okToContinue = false;
                        }
                    }
                    #endregion
                }
                #endregion

                #region Importing Reports
                try
                {
                    SMSReportingFormat SMSFormat = SMSReportingFormat.FLEXIBLE;
                    DataInputingMethod inputMethod = DataInputingMethod.DESKTOP_DATA_MERGING;

                    foreach (string text in reportingTexts)
                    {
                        string reportingText = text;
                        //ReportingMessage reportingMessage = Utilities.SendReport(senderNum, reportingText/*, user.UserSignature*/, false);
                        DataModels.Common.ReportingMessage reportingMessage = Merging.SendReport(senderNum, reportingText, SMSFormat, inputMethod);
                        totalSubmitted++;
                        if (reportingMessage.Status == ReportProcessing.ReportProcessor.NO_ERROR_LABEL)
                        {
                            merged = true;
                            totalReportAccepted++;
                        }
                        else
                        {
                            if (reportingMessage.Status == ReportProcessing.ReportProcessor.REPORT_ALREADY_SUBMITTED_LABEL)
                            {
                                totalAlreadyExisting++;
                                if (overwrite)
                                {
                                    reportingText = String.Format("{0},RESUBMIT", reportingText);
                                    reportingMessage = Merging.SendReport(senderNum, reportingText, SMSFormat, inputMethod);
                                    //reportingMessage = Utilities.SendReport(senderNum, reportingText/*, user.UserSignature*/, false);
                                    if (reportingMessage.Status == ReportProcessing.ReportProcessor.NO_ERROR_LABEL)
                                    {
                                        merged = true;
                                        totalReportAccepted++;
                                        totalReportOverwritten++;
                                    }
                                    else
                                    {
                                        merged = false;
                                        totalRejected++;
                                    }
                                }
                                else
                                {
                                    merged = true;
                                    totalRejected++;
                                }
                            }
                            else
                            {
                                merged = false;
                                totalRejected++;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    merged = false;
                    Utilities.LogError(ex, null);
                }
                #endregion
            }
            catch (Exception ex)
            {
                merged = false;
                Utilities.LogError(ex, null);
            }

            var mergingStatus = new GenericTools.Models.MergingOperationStatus
            {
                TotalAlreadyExisting = totalAlreadyExisting,
                TotalRejected = totalRejected,
                TotalReportAccepted = totalReportAccepted,
                TotalReportOverwritten = totalReportOverwritten,
                TotalSubmitted = totalSubmitted,
                Merged = merged
            };
            return mergingStatus;
        }

        /// <summary>
        /// Merges the reports based on particular definition of merging mergeId
        /// </summary>
        /// <param name="mergeId"></param>
        /// <param name="overwrite"></param>
        /// <param name="facilityCode"></param>
        /// <param name="startYear"></param>
        /// <param name="startMonth"></param>
        /// <param name="endYear"></param>
        /// <param name="endMonth"></param>
        /// <param name="senderNum"></param>
        /// <returns></returns>
        /// <exception cref="System.OutOfMemoryException">
        /// The implementation of this method has the potential circular reference i.e. hence no exit from this function.
        /// Only valid data can prevent that scenario because the changes are cascaded into component reports.
        /// Example of condition which will cause infinite method calling is the following sets of reports
        /// R3 = f(R1,R2), R5 = f(R3,R4) and R1 = f(R5,R6). 
        /// If R5 or R6 is modified, it sets the chain that will affect R1->R3->R5->R1, 
        /// hence infinity loop, no exit, only when the system crush after running out of memory!!!
        /// </exception>
        public static GenericTools.Models.MergingOperationStatus MergeFacilityReports(int mergeId, bool overwrite, string facilityCode, int startYear,
            int startMonth, int endYear, int endMonth, string senderNum)
        {
            switch (AppConfiguration.AccessMethod)
            {
                case DataAccessMethod.DIRECT_ACCESS:
                case DataAccessMethod.OFFLINE_DIRECT_ACCESS:
                    DataTable requiredFacilities = requiredFacilities = Utilities.GetFacilityDetails(facilityCode);
                    var status = MergeReports(mergeId, overwrite, requiredFacilities, startYear, startMonth, endYear, endMonth, senderNum);
                    return status;

                case DataAccessMethod.OFFLINE_DATA_ACCESS:
                    throw new NotImplementedException("This feature does not support MS Access back-end");

                case DataAccessMethod.WEB_SERVICES:
                    var output = webService.MergeFacilityReports(mergeId, overwrite, facilityCode, startYear, startMonth, endYear, endMonth, senderNum);
                    var result = new Models.MergingOperationStatus
                    {
                        Merged = output.Merged,
                        TotalAlreadyExisting = output.TotalAlreadyExisting,
                        TotalRejected = output.TotalRejected,
                        TotalReportAccepted = output.TotalReportAccepted,
                        TotalReportOverwritten = output.TotalReportOverwritten,
                        TotalSubmitted = output.TotalSubmitted
                    };
                    return result;
            }
            return null;
        }

        public static GenericTools.Models.MergingOperationStatus MergeDistrictReports(int mergeId, bool overwrite, int districtId, int startYear,
            int startMonth, int endYear, int endMonth, string senderNum)
        {
            switch (AppConfiguration.AccessMethod)
            {
                case DataAccessMethod.DIRECT_ACCESS:
                case DataAccessMethod.OFFLINE_DIRECT_ACCESS:
                    DataTable requiredFacilities = Utilities.GetFacilitiesDetailsByDistrict(districtId, true);
                    var status = MergeReports(mergeId, overwrite, requiredFacilities, startYear, startMonth, endYear, endMonth, senderNum);
                    return status;

                case DataAccessMethod.OFFLINE_DATA_ACCESS:
                    throw new NotImplementedException("This feature does not support MS Access back-end");

                case DataAccessMethod.WEB_SERVICES:
                    var output = webService.MergeDistrictReports(mergeId, overwrite, districtId, startYear, startMonth, endYear, endMonth, senderNum);
                    var result = new Models.MergingOperationStatus
                    {
                        Merged = output.Merged,
                        TotalAlreadyExisting = output.TotalAlreadyExisting,
                        TotalRejected = output.TotalRejected,
                        TotalReportAccepted = output.TotalReportAccepted,
                        TotalReportOverwritten = output.TotalReportOverwritten,
                        TotalSubmitted = output.TotalSubmitted
                    };
                    return result;
            }
            return null;            
        }

        public static GenericTools.Models.MergingOperationStatus MergeRegionReports(int mergeId, bool overwrite, int regionId, int startYear,
            int startMonth, int endYear, int endMonth, string senderNum)
        {
            switch (AppConfiguration.AccessMethod)
            {
                case DataAccessMethod.DIRECT_ACCESS:
                case DataAccessMethod.OFFLINE_DIRECT_ACCESS:
                    DataTable requiredFacilities = Utilities.GetFacilitiesDetailsByRegion(regionId, true);
                    var status = MergeReports(mergeId, overwrite, requiredFacilities, startYear, startMonth, endYear, endMonth, senderNum);
                    return status;

                case DataAccessMethod.OFFLINE_DATA_ACCESS:
                    throw new NotImplementedException("This feature does not support MS Access back-end");

                case DataAccessMethod.WEB_SERVICES:
                    var output = webService.MergeRegionReports(mergeId, overwrite, regionId, startYear, startMonth, endYear, endMonth, senderNum);
                    var result = new Models.MergingOperationStatus
                    {
                        Merged = output.Merged,
                        TotalAlreadyExisting = output.TotalAlreadyExisting,
                        TotalRejected = output.TotalRejected,
                        TotalReportAccepted = output.TotalReportAccepted,
                        TotalReportOverwritten = output.TotalReportOverwritten,
                        TotalSubmitted = output.TotalSubmitted
                    };
                    return result;
            }
            return null;     

            
        }

        public static GenericTools.Models.MergingOperationStatus MergeNationReports(int mergeId, bool overwrite, int startYear,
            int startMonth, int endYear, int endMonth, string senderNum)
        {
            switch (AppConfiguration.AccessMethod)
            {
                case DataAccessMethod.DIRECT_ACCESS:
                case DataAccessMethod.OFFLINE_DIRECT_ACCESS:
                    DataTable requiredFacilities = Utilities.GetAllFacilitiesStatus();
                    var status = MergeReports(mergeId, overwrite, requiredFacilities, startYear, startMonth, endYear, endMonth, senderNum);
                    return status;

                case DataAccessMethod.OFFLINE_DATA_ACCESS:
                    throw new NotImplementedException("This feature does not support MS Access back-end");

                case DataAccessMethod.WEB_SERVICES:
                    var output = webService.MergeNationReports(mergeId, overwrite, startYear, startMonth, endYear, endMonth, senderNum);
                    var result = new Models.MergingOperationStatus
                    {
                        Merged = output.Merged,
                        TotalAlreadyExisting = output.TotalAlreadyExisting,
                        TotalRejected = output.TotalRejected,
                        TotalReportAccepted = output.TotalReportAccepted,
                        TotalReportOverwritten = output.TotalReportOverwritten,
                        TotalSubmitted = output.TotalSubmitted
                    };
                    return result;
            }
            return null;              
        }
    }
}
